13. Web Services

Web services are all about providing a web API onto your web application and are typically implemented in either SOAP or REST.

웹서비스라는것은 웹 어플리케이션에 대한 웹 API를 제공하는 것에 대한 모든것을 말한다. 이것은 일반적으로 SOAPREST로 구현한다.

13.1 REST

REST는 사실 그 자체로는 어떠한 기술도 아니고 구조적인 형태이다. REST는 매우 간단하고 URL형태와 결합된 보통의 XML이나 JSON을 통신 매체로 사용하는 것이다. 이 URL 형태은 기존(underlying) 시스템의 “표현(representational)“과 GET, PUT, POST, DELETE와 같은 HTTP 메소드을 의미한다.

각 HTTP메소드는 하나의 액션에 연결된다. 예를들어 GET은 데이터를 얻어오기위해, PUT은 데이터를 생성하기위해, POST는 데이터를 수정하기위해, DELETE는 데이터를 삭제하기위해 사용한다. 이러한 점에서, REST는 CRUD에 매우 잘 들어맞는다.

URL patterns(URL 패턴)

Grails로 REST를 구현하기위한 첫번째 과정은 RESTful URL 매핑(URL mappings)을 제공하는것이다:

static mappings = {
   "/product/$id?"(controller:"product"){
       action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
   }	
}

컨트롤러에게 RESTful API를 제공하기 위해 HTTP메소드에 매핑하는 URL 매핑(map to HTTP methods)의 기능을 사용했다. GET, PUT, POST, DELETE 같은 각 HTTP 메소드들은 Controller의 액션에 매핑된다.

XML Marshaling - Reading(XML 마샬링 - 읽기)

컨트롤러의 GET 메소드 액션은 Grail의 XML 마셜링(XML marshaling) 기능을 사용하여 구현할 수 있다:

import grails.converters.*
class ProductController {
	def show = {
		if(params.id && Product.exists(params.id)) {
			def p = Product.findByName(params.id)
			render p as XML
		}
		else {
			def all = Product.list()
			render all as XML
		}
	}
	..
}

이제 만약 좀 더 해야 할 일이 있다면 이름으로 제품의 id을 찾아 반환하거나 모든 제품을 반한하는 것이다. 이 방식에서 /products 로 간다면 모든 제품을 얻을 것이고, 아니면 /products/MacBook으로 간다면 하나의 MacBook만을 얻을 것이다.

XML Marshalling - Updating(XMl 마샬링 - 업데이트)

PUT과 POST 같은 업데이트를 지원하기 위해서 params 객체를 쓸 수 있다. params 객체는 XML로부터 들어오는 정보를 Grails가 접근하기 쉽도록 개선해놓은 것이다. 다음과 같은 들어오는 XML 패킷이 있다:

<?xml version="1.0" encoding="ISO-8859-1"?>
<product>
	<name>MacBook</name>
	<vendor id="12">
		<name>Apple</name>
     </vender>
</product>

데이터 바인딩 절에서 설명한 기술을 이용하는 params 객체를 통해 이 XML 패킷을 읽을 수 있다:

def save = {
	def p = new Product(params['product'])

if(p.save()) { render p as XML } else { def errors = p.errors.allErrors.collect { g.message(error:it) } render(contentType:"text/xml") { error { for(err in errors) { message(error:err) } } } } }

이 예제에서 params 객체속에서 'project'키를 사용하여 인덱싱함으로써 Product 클래스의 생성자를 이용하여 xml을 자동으로 생성하고 바인딩할 수 있다. 아래 코드는 그 예제이다:

def p = new Product(params['product'])

폼 데이터를 전송하는 코드와 XML 요청을 다루는 코드 모두 수정할 필요 없고 XML 요청 뿐만아니라 JSON 요청에도 동일한 방법을 사용할 수 있다.

만약 여러 클라이언트(REST, HTML 기타)에 대해 여러 응답이 필요하다면 컨텐츠 협상(content negotation)을 사용할 수 있음

그래서 Product 객체는 XML로 저장되고 표현되며, 그렇지 않으면 오류 메시지가 생성된다. 오류 메시지는 Grails의 검증(validation)지원을 사용하여 아래와 같은 형식으로 표현된다:

<error>
   <message>The property 'title' of class 'Person' must be specified</message>
</error>

13.2 SOAP

Grails는 XFire 플러그인을 통해 SOAP를 지원한다. XFire플러그인은 많이 쓰이는 XFire SOAP스택을 사용하여 Grails에 SOAP지원을 통합시켜준다. XFire 플러그인은 expose 속성을 사용하여 Grails 서비스를 SOAP 서비스(services)로 노출시켜준다:

class BookService {

static expose=['xfire']

Book[] getBooks(){ Book.list() as Book[] } }

WSDL은 다음과 같은 URL로 접근가능하다.

XFire 플러그인에 대한 정보는 위키의 문서를 참고하라.

13.3 RSS and Atom

Grails에서 RSS나 Atom에 대한 직접적인 지원은 없다. render의 xml 지원을 사용하여 RSS나 ATOM 피드를 만들 수 있다. 하지만 Grails에서 사용할 수 있는 Feed 플러그인 을 사용하여 RSS나 Atom피드를 제공할 수 있다. 이 플러그인은 "ROME"":https://rome.dev.java.net/ 라이브러리를 이용하여 피드를 생성한다. 아래에 그 사용 예제가 있다:

def feed = {
    render(feedType:"rss", feedVersion:"2.0") {
        title = "My test feed"
        link = "http://your.test.server/yourController/feed"

Article.list().each() { entry(it.title) { link = "http://your.test.server/article/${it.id}" it.content // return the content } } } }